﻿using System;
using System.Collections.Generic;
using System.Reflection;
using msilgc.cbuilder.CSyntaxTree;
using msilgc.cbuilder.MSILSyntaxTree;
using msilgc.common;
using msilgc.CSyntaxTree;

namespace msilgc.cbuilder.CBuilder
{
    internal class MethodCallTranslator : ITranslator
    {
        private readonly VariableFactory _varFactory;

        public MethodCallTranslator(VariableFactory varFactory)
        {
            _varFactory = varFactory;
        }

        public ICStatement TranslateAndAdd(
            CMethodBody methodBody, CBasicBlock currentBlock, 
            BasicBlock block, Instruction instruction)
        {
            if(instruction.MethodOperand == null)
            {
                throw new ArgumentException("call instruction does not have a method operand", "instruction");
            }
            MethodBase method = instruction.MethodOperand;
            ParameterInfo[] parameters = method.GetParameters();
            if(method.DeclaringType != typeof(DeviceMethods))
            {
                throw new Exception("Support for methods not declared on DeviceMethods is not yet supported");
            }
            IDictionary<ParameterInfo, IVariable> pVar = new Dictionary<ParameterInfo, IVariable>(parameters.Length);
            foreach (ParameterInfo parameter in parameters)
            {
                pVar.Add(parameter, EvaluationStackHelper.PopVariableOffEvaluationStack(currentBlock));
            }
            Type returnType = ((MethodInfo)method).ReturnType;
            IVariable returnVar = null;
            if (returnType != typeof(void))
            {
                returnVar = _varFactory.CreateNext(returnType);
            }
            ICStatement stm = new CMethodCall(method, pVar, returnVar);
            currentBlock.Statements.Add(stm);
            return stm;
        }
    }
}
